﻿using csLTDMC;
using DingVision.Infrastructure.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace DingVision.Axis.Models
{
    public class DmcCard
    {
        #region 事件
        public delegate void StatusUpdateHandler(object sender, string status);
        public event StatusUpdateHandler StatusUpdate;
        #endregion
        #region 属性
        public ushort CardId { get; set; }
        private bool openCardOk = false;

        public bool OpenCardOk
        {
            get { return openCardOk; }
            set
            {
                openCardOk = value;
                StatusUpdate(this, openCardOk ? "连接" : "断开");
            }
        }

        #endregion
        #region 实例化
        private static DmcCard _instance;
		private static object _lock = new object();
		public static DmcCard Instance
		{
			get
			{
				if (DmcCard._instance == null)
				{
					object @lock = DmcCard._lock;
					lock (@lock)
					{
						if (DmcCard._instance == null)
						{
							DmcCard._instance = new DmcCard();
						}
					}
				}
				return DmcCard._instance;
			}
		}
		#endregion
		#region 变量
        public AxisParm Axis1;
        public AxisParm Axis2;
        public AxisParm Axis3;
        public AxisParm Axis4;
        public AxisParm Axis5;
        public AxisParm Axis6;
        public AxisParm Axis7;
        public AxisParm Axis8;
        #endregion
        #region 当前坐标
        public double PulsePos_Axis1
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 0) * this.Axis1.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 0, (int)(value / this.Axis1.Equiv));
            }
        }

        public double EncPos_Axis1
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 0) * this.Axis1.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 0, (int)(value / this.Axis1.Equiv));
            }
        }
        public double PulsePos_Axis2
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 1) * this.Axis2.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 1, (int)(value / this.Axis2.Equiv));
            }
        }

        public double EncPos_Axis2
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 1) * this.Axis2.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 1, (int)(value / this.Axis2.Equiv));
            }
        }
        public double PulsePos_Axis3
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 2) * this.Axis3.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 2, (int)(value / this.Axis3.Equiv));
            }
        }

        public double EncPos_Axis3
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 2) * this.Axis3.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 2, (int)(value / this.Axis3.Equiv));
            }
        }
        public double PulsePos_Axis4
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 3) * this.Axis4.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 3, (int)(value / this.Axis4.Equiv));
            }
        }

        public double EncPos_Axis4
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 3) * this.Axis4.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 3, (int)(value / this.Axis4.Equiv));
            }
        }
        public double PulsePos_Axis5
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 4) * this.Axis5.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 4, (int)(value / this.Axis5.Equiv));
            }
        }

        public double EncPos_Axis5
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 4) * this.Axis5.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 4, (int)(value / this.Axis5.Equiv));
            }
        }
        public double PulsePos_Axis6
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 5) * this.Axis6.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 5, (int)(value / this.Axis6.Equiv));
            }
        }

        public double EncPos_Axis6
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 5) * this.Axis6.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 5, (int)(value / this.Axis6.Equiv));
            }
        }
        public double PulsePos_Axis7
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 6) * this.Axis7.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 6, (int)(value / this.Axis7.Equiv));
            }
        }

        public double EncPos_Axis7
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 6) * this.Axis7.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 6, (int)(value / this.Axis7.Equiv));
            }
        }
        public double PulsePos_Axis8
        {
            get
            {
                return (double)LTDMC.dmc_get_position(this.CardId, 7) * this.Axis8.Equiv;
            }
            set
            {
                LTDMC.dmc_set_position(this.CardId, 7, (int)(value / this.Axis8.Equiv));
            }
        }

        public double EncPos_Axis8
        {
            get
            {
                return (double)LTDMC.dmc_get_encoder(this.CardId, 7) * this.Axis8.Equiv;
            }
            set
            {
                LTDMC.dmc_set_encoder(this.CardId, 7, (int)(value / this.Axis8.Equiv));
            }
        }
        #endregion
        #region 功能函数
        /// <summary>
        /// 初始化 
        /// STEP1:读参数
        /// STEP2:初始化卡
        /// </summary>
        public void Init()
        {
            LoadAxisParm();
            OpenCardOk = OpenCard();            
        }
        public bool OpenCard()
        {
            bool result;
            try
            {
                var boardCount = LTDMC.dmc_board_init();
                if (boardCount != 1)
                {
                    if (boardCount == 0)
                    {
                        MessageBox.Show("没有找到控制卡，或者控制卡异常");
                    }
                    result = false;
                }
				else
				{
					ushort num = 0;
					uint[] cardTypeList = new uint[8];
					ushort[] array = new ushort[8];
					if (LTDMC.dmc_get_CardInfList(ref num, cardTypeList, array) != 0)
					{
						result = false;
					}
					else
					{
						this.CardId = array[0];
						short num2 = LTDMC.dmc_download_configfile(this.CardId, Environment.CurrentDirectory + @"\Config\c.ini");
						if (num2 != 0)
						{
							result = false;
						}
						else
						{
							ushort num3 = 1;
							LTDMC.dmc_LinkState(this.CardId, ref num3);
							if (num3 != 0)
							{
								MessageBox.Show("接线盒连接失败!请检查急停是否按下或接线盒与运动控制卡之间的电缆是否正确连接?");
								result = false;
							}
							else
							{
								//num2 = LTDMC.dmc_get_can_state(this.CardId, ref this.Node, ref num3);
								//if (num3 != 1)
								//{
								//	this.Node = 1;
								//	num2 = LTDMC.dmc_set_can_state(this.CardId, this.Node, 1, 0);
								//}
								//if (num2 == 0)
								//{
								//	result = true;
								//}
								//else
								//{
								//	MessageBox.Show("CanOpen连接错误,错误码=" + num2.ToString());
								//	result = false;
								//}
								result = true;
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
				result = false;
			}
			return result;
		}
        public void LoadAxisParm() 
        {
            var axisParmList = JsonHelp.JsonRead<List<AxisParm>>(System.IO.Path.Combine(System.Environment.CurrentDirectory, "AxisParm.json"));
            Axis1 = axisParmList[0];
            Axis2 = axisParmList[1];
            Axis3 = axisParmList[2];
            Axis4 = axisParmList[3];
            Axis5 = axisParmList[4];
            Axis6 = axisParmList[5];
            Axis7 = axisParmList[6];
            Axis8 = axisParmList[7];
        }
        public AxisStatus GetAxisStatus(AxisParm axisParm)
        {
            AxisStatus result = default(AxisStatus);
            ushort cardNo = axisParm.CardNo;
            ushort axisId = axisParm.AxisId;
            if (LTDMC.dmc_read_sevon_pin(cardNo, axisId) == 0)
            {
                result.FlagServoOn = true;
            }
            else
            {
                result.FlagServoOn = false;
            }
            uint num = LTDMC.dmc_axis_io_status(cardNo, axisId);
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 0.0)))) == 0UL)
            {
                result.FlagAlm = false;
            }
            else
            {
                result.FlagAlm = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 1.0)))) == 0UL)
            {
                result.FlagPosLimit = false;
            }
            else
            {
                result.FlagPosLimit = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 2.0)))) == 0UL)
            {
                result.FlagNeglimit = false;
            }
            else
            {
                result.FlagNeglimit = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 3.0)))) == 0UL)
            {
                result.FlagEmgStop = false;
            }
            else
            {
                result.FlagEmgStop = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 4.0)))) == 0UL)
            {
                result.FlagHome = false;
            }
            else
            {
                result.FlagHome = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 6.0)))) == 0UL)
            {
                result.FlagPosSoftLim = false;
            }
            else
            {
                result.FlagPosSoftLim = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 7.0)))) == 0UL)
            {
                result.FlagNegSoftLim = false;
            }
            else
            {
                result.FlagNegSoftLim = true;
            }
            if (((ulong)num & (ulong)((long)((int)Math.Pow(2.0, 11.0)))) == 0UL)
            {
                result.FlagSmoothStop = false;
            }
            else
            {
                result.FlagSmoothStop = true;
            }
            if (LTDMC.dmc_check_done(axisParm.CardNo, axisParm.AxisId) == 0)
            {
                result.FlagMoveEnd = false;
            }
            else
            {
                result.FlagMoveEnd = true;
            }
            int num2 = LTDMC.dmc_get_position(axisParm.CardNo, axisParm.AxisId);
            result.PrfPos = (double)num2 * axisParm.Equiv;
            int num3 = LTDMC.dmc_get_encoder(axisParm.CardNo, axisParm.AxisId);
            result.EncPos = (double)num3 * axisParm.Equiv;
            return result;
        }
        public void ServoOn(AxisParm axisParm)
        {
            LTDMC.dmc_write_sevon_pin(axisParm.CardNo, axisParm.AxisId, 0);
        }
        public void ServoOff(AxisParm axisParm)
        {
            LTDMC.dmc_write_sevon_pin(axisParm.CardNo, axisParm.AxisId, 1);
        }
        public void ClearAlm(AxisParm axisParm)
        {
            this.ServoOff(axisParm);
            LTDMC.dmc_write_erc_pin(axisParm.CardNo, axisParm.AxisId, 0);
            Thread.Sleep(1000);
            LTDMC.dmc_write_erc_pin(axisParm.CardNo, axisParm.AxisId, 1);
            this.ServoOn(axisParm);
        }
        public short GetDi(ushort bitno)
        {
            short result = 1;
            if (bitno < 16)
            {
                result = LTDMC.dmc_read_inbit(this.CardId, bitno);
            }
            //else if (bitno > 15 && bitno < 32)
            //{
            //    ushort bitno2 = Convert.ToUInt16((int)(bitno - 16));
            //    result = LTDMC.dmc_read_can_inbit(this.CardId, this.Node, bitno2);
            //}
            return result;
        }
        public void SetDo(ushort outbit, ushort value)
        {
            if (outbit < 16)
            {
                LTDMC.dmc_write_outbit(this.CardId, outbit, value);
                return;
            }
            //if (outbit > 15 && outbit < 32)
            //{
            //    LTDMC.dmc_write_can_outbit(this.CardId, this.Node, Convert.ToUInt16((int)(outbit - 16)), value);
            //}
        }
        public uint GetDiPort()
        {
            return LTDMC.dmc_read_inport(this.CardId, 0);
        }
        public uint GetDoPort()
        {
            return LTDMC.dmc_read_outport(this.CardId, 0);
        }
        public void SigAxisHomeMove(AxisParm _axisParam)
        {
            try
            {
                AxisStatus axisStatus = this.GetAxisStatus(_axisParam);
                if (!axisStatus.FlagServoOn)
                {
                    Console.WriteLine("伺服没有使能&Warn");
                    return;
                }
                else if (axisStatus.FlagAlm)
                {
                    Console.WriteLine("伺服已报警&Warn");
                    return;
                }
                LTDMC.dmc_write_sevon_pin(_axisParam.CardNo, _axisParam.AxisId, 0);
                LTDMC.dmc_clear_stop_reason(_axisParam.CardNo, _axisParam.AxisId);
                LTDMC.dmc_set_profile(_axisParam.CardNo, _axisParam.AxisId, _axisParam.HomeLSpd / _axisParam.Equiv, _axisParam.HomeHSpd / _axisParam.Equiv, _axisParam.Acc, _axisParam.Acc, _axisParam.HomeLSpd / _axisParam.Equiv);
                LTDMC.dmc_home_move(_axisParam.CardNo, _axisParam.AxisId);
            }
            catch
            {
            }
        }
        public bool GetHomeStatus(AxisParm _axisParam, out ushort state)
        {
            bool result;
            try
            {
                state = 0;
                LTDMC.dmc_get_home_result(_axisParam.CardNo, _axisParam.AxisId, ref state);
                if (state == 1)
                {
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            catch
            {
                state = 0;
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 绝对运动
        /// </summary>
        /// <param name="_AxisParam"></param>
        /// <param name="givePos"></param>
        /// <param name="speed"></param>
        /// <returns></returns>
        public bool AxisPosMove(AxisParm _AxisParam, double givePos, double speed = 0.0)
        {
            bool result;
            try
            {
                AxisStatus axisStatus = this.GetAxisStatus(_AxisParam);
                double num2 = givePos / _AxisParam.Equiv;
                if (!axisStatus.FlagServoOn)
                {
                    Console.WriteLine("伺服没有使能&Warn");
                    result = false;
                }
                else if (axisStatus.FlagAlm)
                {
                    Console.WriteLine("伺服已报警&Warn");
                    result = false;
                }
                else
                {
                    double max_Vel;
                    if (speed == 0.0)
                    {
                        max_Vel = _AxisParam.MaxWorkSpd / _AxisParam.Equiv;
                    }
                    else
                    {
                        max_Vel = speed / _AxisParam.Equiv;
                    }
                    LTDMC.dmc_set_profile(_AxisParam.CardNo, _AxisParam.AxisId, 0.0, max_Vel, _AxisParam.Acc, _AxisParam.Acc, 0.0);
                    LTDMC.dmc_set_s_profile(_AxisParam.CardNo, _AxisParam.AxisId, 0, 0.1);
                    if (LTDMC.dmc_pmove(_AxisParam.CardNo, _AxisParam.AxisId, (int)num2, 1) == 0)//这里模式=1，代表绝对坐标（基于规划位置坐标）
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }
                }
                
            }
            catch
            {
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 相对运动
        /// </summary>
        /// <param name="_AxisParam"></param>
        /// <param name="giveDis"></param>
        /// <param name="speed"></param>
        /// <returns></returns>
        public bool AxisTrapMove(AxisParm _AxisParam, double giveDis, double speed = 0.0)
        {
            bool result;
            try
            {
                DmcCard.AxisStatus axisStatus = this.GetAxisStatus(_AxisParam);
                double num = giveDis / _AxisParam.Equiv;
                if (!axisStatus.FlagServoOn)
                {
                    Console.WriteLine("伺服没有使能&Warn");
                    result = false;
                }
                else if (axisStatus.FlagAlm)
                {
                    Console.WriteLine("伺服已报警&Warn");
                    result = false;
                }
                else
                {
                    double max_Vel;
                    if (speed == 0.0)
                    {
                        max_Vel = _AxisParam.MaxWorkSpd / _AxisParam.Equiv;
                    }
                    else
                    {
                        max_Vel = speed / _AxisParam.Equiv;
                    }
                    LTDMC.dmc_set_profile(_AxisParam.CardNo, _AxisParam.AxisId, 0.0, max_Vel, _AxisParam.Acc, _AxisParam.Acc, 0.0);
                    if (LTDMC.dmc_pmove(_AxisParam.CardNo, _AxisParam.AxisId, (int)num, 0) == 0)//这里模式=1，代表相对坐标
                    {
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }
                }
            }
            catch
            {
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 检测动作是否完成，回零、运动都可以使用
        /// </summary>
        /// <param name="_AxisParam"></param>
        /// <returns></returns>
        public bool AxisCheckDone(AxisParm _AxisParam)
        {
            return LTDMC.dmc_check_done(_AxisParam.CardNo, _AxisParam.AxisId) == 1;//0： 指定轴正在运行， 1： 指定轴已停止
        }
        public short AxisJog(AxisParm _AxisParam, ushort dir, double spd = 0.0)
        {
            ushort cardNo = _AxisParam.CardNo;
            ushort axisId = _AxisParam.AxisId;
            short result;
            try
            {
                if (!this.GetAxisStatus(_AxisParam).FlagServoOn)
                {
                    Console.WriteLine("伺服没有使能!&Warn");
                }
                if (this.GetAxisStatus(_AxisParam).FlagAlm)
                {
                    Console.WriteLine("伺服已报警!&Warn");
                }
                double max_Vel;
                if (spd == 0.0)
                {
                    max_Vel = _AxisParam.MaxWorkSpd / _AxisParam.Equiv;
                }
                max_Vel = spd / _AxisParam.Equiv;
                LTDMC.dmc_set_profile(cardNo, axisId, 0.0, max_Vel, 0.1, 0.1, 0.0);
                result = LTDMC.dmc_vmove(cardNo, axisId, dir);//dir 0：负方向， 1：正方向
            }
            catch (Exception)
            {
                result = 2;
            }
            return result;
        }
        public bool AxisStop(ushort CardNo, ushort type)
        {
            short num = 0;
            for (ushort num2 = 0; num2 < 8; num2 += 1)
            {
                if (type == 0)
                {
                    num = LTDMC.dmc_stop(CardNo, num2, 0);//制动方式， 0： 减速停止， 1： 紧急停止
                }
                else
                {
                    num = LTDMC.dmc_stop(CardNo, num2, 1);
                }
            }
            return num == 0;
        }
        public bool AxisStop(AxisParm _AxisParam, ushort type)
        {
            ushort cardNo = _AxisParam.CardNo;
            ushort axisId = _AxisParam.AxisId;
            short num;
            if (type == 0)
            {
                num = LTDMC.dmc_stop(cardNo, axisId, 0);
            }
            else
            {
                num = LTDMC.dmc_stop(cardNo, axisId, 1);
            }
            return num == 0;
        }
        #endregion
        #region 数据类型

        public struct AxisStatus
        {
            public bool FlagHome;
            public bool FlagAlm;
            public bool FlagMError;
            public bool FlagPosLimit;
            public bool FlagNeglimit;
            public bool FlagPosSoftLim;
            public bool FlagNegSoftLim;
            public bool FlagEmgStop;
            public bool FlagSmoothStop;
            public bool FlagAbruptStop;
            public bool FlagServoOn;
            public bool FlagMoveEnd;
            public double PrfPos;
            public double EncPos;
            public ushort MoveMode;
        }
        public struct AxisParm
        {
            public ushort CardNo;
            public ushort AxisId;
            public double Equiv;
            public ushort HomeDir;
            public ushort HomeMode;
            public double HomeHSpd;
            public double HomeLSpd;
            public double HomeOffset;
            public double Acc;
            public double MaxWorkSpd;
            public double PosLimit;
            public double NegLimit;
            public bool HomeFinish;
            public DmcCard.AxisStatus AxisSts;
            public double SafePos;
        }
        #endregion
    }
}
